#!/usr/bin/python


"""
Remote file copy utility. It is a wrapper on scp to copy files to remote 
hosts in parallel
"""

import os
import sys
import commands
import threading
import socket
import logging
import time
from optparse import OptionParser

def initialize_logging(fname):
    """ Configure the debugging log configuration when the -l option is specified.
        The log file is stored at the file location listed as the argument to the -l option.
    """

    global logger
    logger = logging.getLogger('rscp')
    logger.setLevel(logging.DEBUG)

    try:
        fileHandler = logging.FileHandler(fname)
    except (IOError, os.error), msg:
        print msg
        sys.exit(-1)
    fileHandler.setLevel(logging.DEBUG)
    logger.addHandler(fileHandler)

def scp_to(src, user, host, dest, opt = "", timeout = 15, retry_count = 5):
    """
    SCP a file from the location of src to the dest location in a remote host
    Arguments:
    - `src`:
    - `user`:
    - `host`:
    - `dest`:
    - `opt`:
    - `timeout`:
    - `retry_count`:
    """

    for i in xrange(retry_count):
        cmd = ("scp -r %s -o StrictHostKeyChecking=no -o ConnectTimeout=%d "
                " %s %s@%s:%s " % (opt, timeout, src, user, host, dest))
        status, output = commands.getstatusoutput(cmd)
        if status == 0:
            return (status, output)
    return (status, output)

class copy(threading.Thread):
    
    def __init__(self, host, src, dest, print_ret_val = False):
        threading.Thread.__init__(self)
        self.host = host
        self.src = src
        self.dest = dest

    def run(self):
        user = "swift"
        ret, out = scp_to(self.src, user, self.host, self.dest, 
                                opt="-q", retry_count=2)
        if  ret != 0 :
            print "\nOutput from host : %s \n\t%s" %(self.host, out)
        if print_ret_val:
            print "\nReturn value from host %s is %d" %(self.host, ret)


def mscp(hosts, src, dest, print_ret_val):
    
    threads = []
    for h in hosts:
        t = copy(h, src, dest, print_ret_val)
        threads.append(t) 
        t.start()
    
    # wait for the threads to finish
    for t in threads:
        t.join()

def read_hosts_file(fname):
    """ Create a list of host_names or ip's from the file
        The file should have one and only one hostname or ip per line
    """    

    hosts_lst=[]
    try:
        f = open(fname, 'r')  
    except (IOError, os.error), msg:
        print msg
        sys.exit(-1)
    else:
        for line in f:
            line = line.strip()
            if line.startswith("#") or line=="":
                continue
            else:
                hosts_lst.append(line)

    return hosts_lst

if __name__ == '__main__':

    usage = r"""
    %prog [options] src dest

    src     source file
    dest    destination 
    
    When no option is specified, the file is copied to all the 
    nodes in /etc/hosts
    """ 

    parser = OptionParser(usage=usage)
    parser.add_option("-f", "--file", dest="filename",
                      help="Read data from FILENAME. Each line in the file should "
                            " be a valid host name")
    parser.add_option("-n", "--hosts", dest="hosts",
                        help="Comma separated list of host names or "
                                "IP addresses")
    parser.add_option("-e", dest="prtret", action="store_true",
                      help="Print the return value of the command executed on the hosts")
    parser.add_option("-X", "--except", dest="notme", action="store_true",
                      help="Skip invocation of the copy on the host running this program")
   
    (options, args) = parser.parse_args()
    if len(args) != 2:
        parser.print_help()
        sys.exit(-1)
    
    src = args[0]
    dest = args[1]

    # Build the target list
    if options.filename:
        hosts = read_hosts_file(options.filename)
    elif options.hosts:
        hosts = options.hosts.split(',')
    else:
        print "invalid input"
        sys.exit(1)

    # filter out myself if requested
    if options.notme:
        myhost = socket.gethostname()
        hosts = [item for item in hosts if item != myhost]

    print_ret_val = False
    if options.prtret:
        print_ret_val = True

    mscp(hosts, src, dest, print_ret_val)
